package com.ljh.nio.c3;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

import static com.ljh.nio.c1.ByteBufferUtil.debugAll;
import static com.ljh.nio.c1.ByteBufferUtil.debugRead;


/**
 * @author: Themberfue
 * @date: 2025/5/26 14:35
 * @description:
 */
public class ServerSelector2 {
    private static final Logger log = LoggerFactory.getLogger(ServerSelector2.class);

    public static void split(ByteBuffer source) {
        source.flip();
        for (int i = 0; i < source.limit(); i++) {
            if (source.get(i) == '\n') {
                int length = i - source.position() + 1;
                ByteBuffer target = ByteBuffer.allocate(length);
                for (int j = 0; j < length; j++) {
                    target.put(source.get());
                }
                debugAll(target);
            }
        }
        source.compact();
    }

    public static void main(String[] args) throws IOException {
        // TODO 1. 创建 selector，管理多个 Channel
        Selector selector = Selector.open();

        ServerSocketChannel ssc = ServerSocketChannel.open();
        ssc.configureBlocking(false);

        // TODO 2. 建立 selector 和 channel 的联系（注册）
        // ! SelectionKey 就是将来建立连接后，可以通过它知道是哪个事件和哪个 channel 的事件
        // ? ops：事件 => accept、connect、read、write
        SelectionKey sscKey = ssc.register(selector, 0, null);
        log.debug("{}", sscKey);

        // TODO 3. 该 key 只关注 accept 事件
        sscKey.interestOps(SelectionKey.OP_ACCEPT);

        ssc.bind(new InetSocketAddress(8080));

        while (true) {
            // TODO 4. select()，没有事件发生，线程阻塞；有事件，线程才会恢复运行
            // ! select 在事件未处理时，不会阻塞，而是接着执行下去。事件要么处理，要么取消，不能置之不理！
            selector.select();

            // TODO 5. 处理事件，selectedKeys 包含了内部的所有事件
            // ! 需要处理的事件（包括之前未处理的，会重新放入）会将由 selector 放进 selectedKeys 里
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator(); // ? accept，read
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                // ! selector 的 selectedKeys 是一个集合，默认不会清空，如果你不手动 remove，每次 select() 之后它都还在，就会重复处理老事件。
                iterator.remove();
                log.debug("{}", key);

                // TODO 6. 区分事件类型
                if (key.isAcceptable()) {
                    ServerSocketChannel channel = (ServerSocketChannel) key.channel();
                    // ? 接收一个客户端连接
                    SocketChannel sc = channel.accept();
                    log.debug("{}", sc);
                    sc.configureBlocking(false);
                    // ? 然后注册到 selector，表示我想关注“这个连接是否有数据可读”。
                    SelectionKey scKey = sc.register(selector, 0, null);
                    scKey.interestOps(SelectionKey.OP_READ); // ? 该次接受连接的 channel 关注 read
                } else if (key.isReadable()) {
                    try {
                        // TODO 读取数据
                        // ? 该 key 为 read 事件的，因此只需 SocketChannel 即可
                        SocketChannel channel = (SocketChannel) key.channel();
                        ByteBuffer buffer = ByteBuffer.allocate(16);
                        int read = channel.read(buffer); // ! 正常断开，返回 -1
                        if (read == -1) {
                            key.cancel(); // ! 正常断开后，越需要将 key 取消
                        } else {
//                            buffer.flip();
//                            debugRead(buffer);
                            split(buffer);
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                        key.cancel(); // ! 因为客户端断开了，需要将 key 取消（从 selector 的 keys 集合中真正删除 key）
                    }
                }
            }
        }
    }
}
